<template>
  <el-dialog class="nodeImportDialog" title="导入" v-model="dialogVisible" width="300px">
    <el-upload
      ref="upload"
      action="x"
      :file-list="fileList"
      :auto-upload="false"
      :multiple="false"
      :on-change="onChange"
      :limit="1"
      :on-exceed="onExceed"
    >
      <el-button type="primary">选取文件</el-button>
      <template #tip> <div class="tip">支持.smm、.json、.xmind、.xlsx、.md文件</div> </template>
    </el-upload>
    <template v-slot:footer>
      <el-button @click="cancel">取消</el-button>
      <el-button type="primary" @click="confirm">确定</el-button>
    </template>
  </el-dialog>
</template>

<script>
import xmind from "simple-mind-map/src/parse/xmind.js"
import markdown from "simple-mind-map/src/parse/markdown.js"
import { fileToBuffer } from "../../../utils"
import { read, utils } from "xlsx"
import { ElMessage } from "element-plus"

/**
 * @Desc: 导入
 */
export default {
  name: "Import",
  data() {
    return {
      dialogVisible: false,
      fileList: []
    }
  },
  watch: {
    dialogVisible(val, oldVal) {
      if (!val && oldVal) {
        this.fileList = []
      }
    }
  },
  created() {
    this.$bus.$on("showImport", this.handleShowImport)
    this.$bus.$on("handle_file_url", this.handleFileURL)
  },
  beforeUnmount() {
    this.$bus.$off("showImport", this.handleShowImport)
    this.$bus.$off("handle_file_url", this.handleFileURL)
  },
  methods: {
    handleShowImport() {
      this.dialogVisible = true
    },

    // 检查url中是否操作需要打开的文件
    async handleFileURL() {
      try {
        const fileURL = this.$route.query.fileURL
        if (!fileURL) return
        const macth = /\.(smm|json|xmind|md|xlsx)$/.exec(fileURL)
        if (!macth) {
          return
        }
        const type = macth[1]
        const res = await fetch(fileURL)
        const file = await res.blob()
        const data = {
          raw: file
        }
        if (type === "smm" || type === "json") {
          this.handleSmm(data)
        } else if (type === "xmind") {
          this.handleXmind(data)
        } else if (type === "xlsx") {
          this.handleExcel(data)
        } else if (type === "md") {
          this.handleMd(data)
        }
      } catch (error) {
        console.log(error)
      }
    },

    onChange(file) {
      const reg = /\.(smm|xmind|json|xlsx|md)$/
      if (!reg.test(file.name)) {
        ElMessage({
          type: "error",
          message: "请选择.smm、.json、.xmind、.xlsx、.md文件"
        })
        this.fileList = []
      } else {
        this.fileList.push(file)
      }
    },

    onExceed() {
      ElMessage({
        type: "error",
        message: "最多只能选择一个文件"
      })
    },

    cancel() {
      this.dialogVisible = false
    },

    confirm() {
      if (this.fileList.length <= 0) {
        ElMessage({
          type: "error",
          message: "请选择要导入的文件"
        })
        return
      }
      const file = this.fileList[0]
      if (/\.(smm|json)$/.test(file.name)) {
        this.handleSmm(file)
      } else if (/\.xmind$/.test(file.name)) {
        this.handleXmind(file)
      } else if (/\.xlsx$/.test(file.name)) {
        this.handleExcel(file)
      } else if (/\.md$/.test(file.name)) {
        this.handleMd(file)
      }
      this.cancel()
    },

    handleSmm(file) {
      const fileReader = new FileReader()
      fileReader.readAsText(file.raw)
      fileReader.onload = (evt) => {
        try {
          const data = JSON.parse(evt.target.result)
          if (typeof data !== "object") {
            throw new Error("文件内容有误")
          }
          console.log("data", data)
          this.$bus.$emit("setData", data)
          ElMessage({
            message: "导入成功",
            type: "success"
          })
        } catch (error) {
          ElMessage({
            message: "导入失败",
            type: "error"
          })
        }
      }
    },

    async handleXmind(file) {
      try {
        const data = await xmind.parseXmindFile(file.raw)
        this.$bus.$emit("setData", data)
        ElMessage({
          message: "导入成功",
          type: "success"
        })
      } catch (error) {
        ElMessage({
          message: "导入失败",
          type: "error"
        })
      }
    },

    async handleExcel(file) {
      try {
        const wb = read(await fileToBuffer(file.raw))
        const data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]], {
          header: 1
        })
        if (data.length <= 0) {
          return
        }
        let max = 0
        data.forEach((arr) => {
          if (arr.length > max) {
            max = arr.length
          }
        })
        const layers = []
        const walk = (layer) => {
          if (!layers[layer]) {
            layers[layer] = []
          }
          for (let i = 0; i < data.length; i++) {
            if (data[i][layer]) {
              const node = {
                data: {
                  text: data[i][layer]
                },
                children: [],
                _row: i
              }
              layers[layer].push(node)
            }
          }
          if (layer < max - 1) {
            walk(layer + 1)
          }
        }
        walk(0)
        const getParent = (arr, row) => {
          for (let i = arr.length - 1; i >= 0; i--) {
            if (row >= arr[i]._row) {
              return arr[i]
            }
          }
        }
        for (let i = 1; i < layers.length; i++) {
          const arr = layers[i]
          for (let j = 0; j < arr.length; j++) {
            const item = arr[j]
            const parent = getParent(layers[i - 1], item._row)
            if (parent) {
              parent.children.push(item)
            }
          }
        }
        this.$bus.$emit("setData", layers[0][0])
        ElMessage({
          message: "导入成功",
          type: "success"
        })
      } catch (error) {
        console.log(error)
        ElMessage({
          message: "导入失败",
          type: "error"
        })
      }
    },

    // 处理markdown文件
    async handleMd(file) {
      const fileReader = new FileReader()
      fileReader.readAsText(file.raw)
      fileReader.onload = async (evt) => {
        try {
          const data = await markdown.transformMarkdownTo(evt.target.result)
          this.$bus.$emit("setData", data)
          ElMessage({
            message: "导入成功",
            type: "success"
          })
        } catch (error) {
          console.log(error)
          ElMessage({
            message: "导入失败",
            type: "error"
          })
        }
      }
    }
  }
}
</script>

<style lang="less" scoped>
.tip {
  font-size: 12px;
}
</style>
